package robot;

/**
 * Servlet WaveEmoticonRobotServlet.
 * This Servlet is waiting for events registered into capabilities.xml file.
 * Every time one of these events raise up, the Servlet will be invoked by the Google Wave 
 * Client where the robot is in action.
 * This Servlet is waiting for new Blips from the users, and when it happens, it check the new 
 * Blip in looking for some matches with the emoticons mapped into map.txt file.
 * @author Mirko Bonadei
 * @version 0.4
 */
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.Vector;

import javax.servlet.http.*;

import com.google.wave.api.AbstractRobotServlet;
import com.google.wave.api.Blip;
import com.google.wave.api.Element;
import com.google.wave.api.Event;
import com.google.wave.api.EventType;
import com.google.wave.api.Image;
import com.google.wave.api.Range;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;

@SuppressWarnings("serial")
public class WaveEmoticonsRobotServlet extends AbstractRobotServlet {

	private static boolean debug = false;
	private static final int version = 1;
	private static final int revision = 0;
	private static final String VERSION_MSG = "Google Wave Emoticon Robot:"
			+ version + "." + revision + ".";
	private static final String MAP_FILE = "data" + File.separator + "map.txt";
	private static final int WIDTH = 24;
	private static final int HEIGTH = 24;
	private static Scanner scan = null;
	private static FileReader file = null;
	private static HashMap<String, Image> map = null;
	private static Emoticon[] keysToCheck;

	/**
	 * Environmet initialization. The robot needs to load the mapped couple
	 * (<Key>\t<ImagePath>) stored into MAP_FILE.
	 */
	static {
		try {
			Vector<Emoticon> tmpVector = new Vector<Emoticon>();
			String tmpCode, tmpPath;
			file = new FileReader(MAP_FILE);
			scan = new Scanner(file);
			map = new HashMap<String, Image>();
			while (scan.hasNext()) {
				tmpCode = scan.next();
				tmpPath = scan.next();
				tmpVector.add(new Emoticon(tmpCode, new Image(tmpPath, WIDTH, HEIGTH, tmpCode)));
				//map.put(tmpCode, new Image(tmpPath, WIDTH, HEIGTH, tmpCode));
			}
			keysToCheck = new Emoticon[tmpVector.size()];
			tmpVector.toArray(keysToCheck);
			Arrays.sort(keysToCheck);
		} catch (FileNotFoundException ex) {
			// TO DO: Fix this situation with a more reliable exit strategy
			System.out.println(ex.getMessage());
		}
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("text/plain");
		resp.getWriter().println("Hello, world");
		resp.getWriter().println("Oggetti mappati: " + this.keysToCheck.length);
	}

	/**
	 * Process all the events that the Robot is following.
	 */
	@Override
	public void processEvents(RobotMessageBundle bundle) {
		/*
		 * just for debugging when the Robot was just added to the Wave, we
		 * print out a version message.
		 */
		if (debug && bundle.wasSelfAdded()) {
			Blip newBlip = bundle.getWavelet().appendBlip();
			newBlip.getDocument().delete(); // fix for issue 354
			TextView newTextView = newBlip.getDocument();
			newTextView.append(this.VERSION_MSG);
		}

		for (Event e : bundle.getEvents()) {
			if (e.getType() == EventType.BLIP_SUBMITTED) { // Every time that a
															// user clik on
															// "DONE"
				Blip toCheck = e.getBlip();
				check(toCheck);
			}
		}
	}

	/**
	 * Check the Blip looking for some matches with the mapped Keys.
	 * 
	 * @param toCheck
	 */
	private void check(Blip toCheck) {
		TextView textView = toCheck.getDocument();
		String text = textView.getText();
		// searching some Emoticons into the original TextView String
		int index = this.keysToCheck.length - 1;
		Vector<Integer> alreadyChecked = new Vector<Integer>();
		Vector<Edit> toEdit = new Vector<Edit>();
		while(index >= 0){
			int pos = -1;
			Emoticon tmpKey = this.keysToCheck[index];
			while(((pos = text.indexOf(tmpKey.getCode(), ++pos)) > -1)){
				if(alreadyChecked.contains(new Integer(pos))){
					continue;
				}
				String tmpSubString = text.substring(pos, pos+tmpKey.getCode().length());
				if(tmpKey.getCode().equals(tmpSubString)){
					toEdit.add(new Edit(pos, pos + tmpKey.getCode().length(), tmpKey));
					alreadyChecked.add(new Integer(pos));
				}
			}
			index--;
		}
		// Now, it's time to update the Blip, but before I have to sort the toEdit istances
		Edit[] edits = new Edit[toEdit.size()];
		toEdit.toArray(edits);
		Arrays.sort(edits);
		for(Edit tmpEdit : edits){
			textView.delete(new Range(tmpEdit.getStartIndex(), tmpEdit.getEndIndex()));
			textView.insertElement(tmpEdit.getStartIndex(), (Element)tmpEdit.getEmoticon().getImage());
		}
	}
}
